package controllers;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.LinkedList;
import java.util.List;

import controllers.CRUD.ObjectType;

import models.Action;
import models.Log;
import models.Notification;
import models.Project;
import models.Role;
import models.User;
import models.UserRoleProject;
import play.db.jpa.JPASupport;
import play.i18n.Messages;
import play.libs.Mail;
import play.mvc.Controller;
import play.mvc.With;
import models.Role;
import play.db.jpa.JPASupport;
import play.exceptions.TemplateNotFoundException;
import play.i18n.Messages;

@With(Secure.class)
@CRUD.For(UserRoleProject.class)
public class UserRoleProjects extends CRUD {
	/**
	 * Renders the list of roles to choose from and the project
	 * 
	 * @param projectId
	 *            the required project
	 * 
	 */
	public static void changeRoleRequest(long projectId) {
		/*
		 * P.S. with each project creation, we need to have
		 * a copy of the built-in roles for it.
		 */
		
		//Security Checking
		Security.checkAccess("Request to change my role in project", projectId, Project.class
				.getName());
		
		// getting the user's id
		long uId = Long.parseLong(session.get("userId"));
		// getting the project
		Project project = Project.findById(projectId);
		// Tuples specific to this project
		List<UserRoleProject> uprList = project.user_project_roles;
		// testing
		// List of roles in the project
		List<Role> rList = new LinkedList<Role>();

		// getting the user's role, so as not to allow him/her to change to
		// current role
		UserRoleProject myRow = UserRoleProject.find(
				"byProject_idAndUser_idAndStatus", projectId, uId, true)
				.first(); // Tuple containing the user's current role in the
		// project
		
		// the role itself
		Role myRole = myRow.role;
		// project admin role
		Role pAdmin = Role.find("byTitle", "Project Admin").first();
		// scrum master role
		Role sMaster = Role.find("byTitle", "Scrum Master").first();
		// checking if a scrum master already exists
		boolean sMasterExists = false; 
		UserRoleProject sMasterRow = UserRoleProject.find(
				"byProject_idAndRole_id", projectId, sMaster.getEntityId())
				.first(); // Tuple containing the user's current role in the
		
		if(sMasterRow != null)
		{
			if(sMasterRow.user != null)
			{
				sMasterExists = true;
			}
		}
		
		for (int i = 0; i < uprList.size(); i++) {
			UserRoleProject row = uprList.get(i);
			Role r = row.role;
			// testing
			
			// to prevent duplicating roles
			if (!rList.contains(r)) {
				// to prevent having the user's same role or having Project Admin
				if (!r.equals(myRole))
					if(!(sMasterExists && r.equals(sMaster)))
						if(!(r.title).equals("Project Admin"))
					rList.add(r);
			}
		}
		
		
		render(myRole,rList, project);
	}

	/**
	 * Submits the actual role change request
	 * 
	 * @param projectId
	 *            the required project
	 * @param role
	 *            the required role to be changed to
	 * 
	 */
	public static void request(long projectId, long role) {

		long uId = Long.parseLong(session.get("userId"));
		User u = User.findById(uId);
		// status will be pending
		boolean status = false;
		Project p = Project.findById(projectId);
		Role chosen = Role.findById(role);
		boolean notifyOldRequest = false;
		Log tmp = new Log((Long) u.getEntityId(), null, null, "Requested to Change Role", projectId, null);
		
		if (chosen != null)
		{
			UserRoleProject pendingUrp = new UserRoleProject(status, u, chosen,p);
			
			// checking if the user has requested Role Change before or not
			UserRoleProject oldRequest = UserRoleProject.find("byProject_idAndUser_idAndStatus", projectId,
					uId, false).first();
			if ( oldRequest!= null)
			{
				//checking if the request is duplicated
				if((pendingUrp.role).equals(oldRequest.role))
				{
					flash.error("You have already made this request before! Please be patient; the Project Admin is going to handle it soon.");
					changeRoleRequest(projectId);
				}
				else
				{// the user had a different old request
					// notify the Project Admin by that
					notifyOldRequest = true;
					flash.success("Change Role Request Successfully Sent! Your old request is now replaced!");
					// record will be saved in database
					pendingUrp.save();
					//LOG
					tmp.save();
				}
			}
			else
				{
					flash.success("Change Role Request Successfully Sent!");
					// record will be saved in database
					pendingUrp.save();
					//LOG
					tmp.save();
				}
			
			// Notify the Project Admin
			Role pAdmin = Role.find("byTitle", "Project Admin").first();
			////User projectAdmin = UserRoleProject
			////		.find(
			////				"select usp.user from UserRoleProject usp where usp.project=? and usp.role= ?",
			////				p, pAdmin).first();
			
			List<UserRoleProject> projectAdminURP = UserRoleProject.find("byProject_idAndStatus", projectId, true).fetch();
			User projectAdmin = null;
			for(int i=0; i<projectAdminURP.size(); i++ )
			{
				Role rTest = projectAdminURP.get(i).role;
				if((rTest.title).equals("Project Admin"))
				{
					projectAdmin = projectAdminURP.get(i).user;
					break;
				}
			}
			
			String message = "User: "
					+ u.userName
					+ ", has requested to change to: "
					+ chosen.title
					+ ", in Project: "
					+ p.name
					+ ".\n"
					+ "To accept or reject follow this link:\n http://localhost:9000/userroleprojects/getallrolerequests?projectId="
					+ projectId;
			
			//In case of an old request
			if(notifyOldRequest)
			{
				message = "The following mail was previously sent to you:-\n"
					+"User: "
					+ u.userName
					+ ", has requested to change to: "
					+ oldRequest.role.title
					+ ", in Project: "
					+ p.name
					+ ".\n"
					+ "To accept or reject follow this link:\n http://localhost:9000/userroleprojects/getallrolerequests?projectId="
					+ projectId+
					"\n+PLEASE IGNORE it.\n The request has changed to:-\n"+message;
				
				//delete old request
				oldRequest.delete();
			}
			
			// if there is a Project Admin
			if (projectAdmin != null)
			{ System.out.println("Entered");
				System.out.println(projectAdmin.email);
				//notify by mail
				Mail.send("coolSoft@SMT.com", projectAdmin.email,"A Change Role Request is awaiting your approval",message);
				//notify by instant notification
				new Notification((Long) projectAdmin.getEntityId(), "New Change Role Request", "A change role request is awaiting your approval").save();
			}
		}
		else
			flash.error("You haven't chosen a Role to Change to!");
		
		//changeRoleRequest(projectId);
		Projects.showProject(projectId);
	}

	/**
	 * Method that renders to the page AcceptRejectRoleRequests.html 2 lists a
	 * list of user and a list of their corresponding role requests
	 * 
	 * @param projectId
	 *            id of project with the requests
	 */

	public static void getAllRoleRequests(long projectId) {
		Project project = Project.findById(projectId);
		List<User> users = User
				.find(
						"select urp.user from UserRoleProject urp where urp.project=? and urp.status=?",
						project, false).fetch();
		List<Role> roles = Role
				.find(
						"select urp.role from UserRoleProject urp where urp.project=? and urp.status=?",
						project, false).fetch();

		render("UserRoleProjects/AcceptRejectRoleRequests.html", users, roles,
				projectId);
	}

	/**
	 * A method that either accepts or reject the request and if it accepts it
	 * removes the old record if rejects it removes the requesting record
	 * 
	 * @param projectId
	 *            id of project with the requests
	 * @param roleId
	 *            id of the role requested
	 * @param userId
	 *            id of the user requesting a certain role
	 * @param accepted
	 *            accepted or rejected request
	 */
	public static void AcceptRejectRoleRequests(long projectId, Long roleId,
			Long userId, boolean accepted) {
		Security.checkAccess("Grant/reject a Project Member role-request", projectId, Project.class
				.getName());
		UserRoleProject urp = UserRoleProject.find(
				"byProject_idAndUser_idAndRole_idAndStatus", projectId, userId,
				roleId, false).first();
		UserRoleProject oldurp = UserRoleProject.find(
				"byProject_idAndUser_idAndStatus", projectId, userId, true)
				.first();
		User user= User.findById(userId);
		Notification not;
		String notify;
		Log log;
		if(accepted)
			notify="accepted";
		else
			notify="rejected";
		Role Admin = Role.find("byTitle", "Project Admin").first();
		User user1= UserRoleProject.find("select u.user from UserRoleProject u where u.role = ?", Admin).first();
		String desc = user.userName + " has " + notify +" Your role request";
		String desc2 = user1.userName + " has " + notify + user.userName +" role request";
		if (accepted == true) {
			urp.status = true;
			oldurp.delete();
			urp.save();
			not =new Notification(userId,"Role Request",desc);
			log = new Log(user1.getId(),urp.role.getId(),"UserRoleProject",desc2,projectId,null);
		} else {
			urp.delete();
			urp.status = false;
			urp.save();
			not =new Notification(userId,"Role Request",desc);
			log = new Log(user1.getId(),null,null,desc2,null,null);
		}
		not.save();
		log.save();
		Projects.showMyProjects();
	}


	
	
	
	
	
}
